/**
 * \file TranslationUnit.cpp
 *
 * Asteriskos Compiler 1
 * Written 2010-2011, by Anthony Berlin and Alexander Carlqvist
 *
 * This file is part of ICC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "TranslationUnit.h"
#include "Error.h"

#include <strutil/strutil.h>

#include <fstream>

///
/// \brief Constructor for \c TranslationUnit.
///
TranslationUnit::TranslationUnit(const char* url, string& appFileName)
{
    TranslationUnit();

    m_path = '\0';
    m_lines = new (GC) list<SourceLine*>;

    if (!sizeof(url))
        return;

    if (!load(url))
        cerr << appFileName << ": Invalid input \"" << url << "\".\n";
}

TranslationUnit::TranslationUnit()
{
    m_path = '\0';
    m_lines = new (GC) list<SourceLine*>;
}

///
/// \brief Load the translation-unit into memory.
///
bool TranslationUnit::load(const char* url)
{
    m_path = url;

    std::ifstream fileStream(url);

    if (!fileStream || !fileStream.is_open())
        return false;

    string peek;
    string* line = new string;
    int lineNumber = 0;

    // Read the translation-unit to memory, one line at a time.
    while (std::getline(fileStream, peek, '\n'))
    {
        // Increase the line number.
        ++lineNumber;

        // Push the line last in the line list.
        strutil::strip_extra_whitespaces(peek, line);
        push_line_last(url, lineNumber, *line);
    }

    delete line;

    fileStream.close();

    return true;
}

///
/// \brief Returns the path of the traslation-unit.
///
string TranslationUnit::get_path() const
{
    if (m_path[0] != '\0')
        return m_path;

    return (string)"";
}

///
/// \brief Set the path of the traslation-unit.
///
void TranslationUnit::set_path(string path)
{
    m_path = path;
}

///
/// \brief Returns the list of lines that the traslation-unit contains.
///
list<SourceLine*>* TranslationUnit::get_lines() const
{
    if (m_path[0] != '\0')
        return m_lines;

    return 0;
}

///
/// \brief Push a new line of data to the last position of 'm_lines'.
///
void TranslationUnit::push_line_last(string filename, unsigned int lineNumber, string data)
{
    if (data.empty())
        return;

    SourceLine* line = new SourceLine;

    line->m_data = data;
    line->m_lineNumber = lineNumber;
    line->m_transUnit = this;
    line->m_originalPath = filename;

    m_lines->push_back(line);
}

///
/// \brief Dump the translation-unit to disc.
///
bool TranslationUnit::dump_to_disc(const char* path, string& appFileName) const
{
    std::ofstream fileStream(path);

    if (!fileStream || !fileStream.is_open())
    {
        cout << appFileName << ": Failed to write to disc.\n";
        return false;
    }

    foreach (SourceLine* curLine, *get_lines())
        fileStream << curLine->m_data << "\n";

    fileStream.close();

    return true;
}
